import { useContext, useMemo, type ReactNode } from "react";
import { GanttConsts } from "../constants";
import { cn } from "../helpers/utils";
import type { TaskMode } from "../types";
import dayjs, { Dayjs } from "dayjs";
import { splitDateRange } from "../helpers/time";
import { getTimeUnitWidth } from "../helpers/utils";
import GanttContext from "../context";

export default function TimeHeader() {
  const { taskMode, tasksStart, tasksEnd, scrollLeft } = useContext(GanttContext);
  const primaryComponents = useMemo(() => {
    const components: ReactNode[] = [];
    const range = splitDateRange(tasksStart, tasksEnd, taskMode);

    if (taskMode === "Day") {
      const totalDays = tasksEnd.diff(tasksStart, "day") + 1;
      const MAX_RENDER_DAYS = 365;

      if (totalDays > MAX_RENDER_DAYS) {
        components.push(
          <div
            key="day-limit-warning"
            className="w-full text-xs flex justify-center items-center bg-red-400 text-white"
            style={{
              width: `${totalDays * getTimeUnitWidth(taskMode)}px`,
              height: `${GanttConsts.THEADER_HEIGHT}px`,
            }}
          >
            时间范围过大 ({totalDays}天)，请缩小范围以提升性能
          </div>
        );
      } else {
        let currentDayDate = tasksStart;
        let i = 0;
        while (currentDayDate <= tasksEnd) {
          components.push(renderDayItem(currentDayDate, i, taskMode));
          i++;
          currentDayDate = currentDayDate.add(1, "day");
        }
      }
    } else {
      range.forEach((item, index) => {
        components.push(
          renderRangeItem(item as [string, string], index, taskMode)
        );
      });
    }

    return components;
  }, [tasksStart, tasksEnd, taskMode]);
  return (
    <div
      className="flex"
      style={{
        transform: `translateX(-${scrollLeft}px)`,
        willChange: "transform",
      }}
    >
      {primaryComponents}
    </div>
  );
}

const getTimeHeaderSplitWidth = (
  taskMode: TaskMode,
  item: [string, string]
) => {
  const timeUnitWidth = getTimeUnitWidth(taskMode);
  return taskMode === "Day"
    ? timeUnitWidth
    : (dayjs(item[1]).diff(dayjs(item[0]), "day") + 1) * timeUnitWidth;
};

const renderDayItem = (date: Dayjs, index: number, taskMode: TaskMode) => {
  const isWeekend = date.isoWeekday() === 6 || date.isoWeekday() === 7;
  return (
    <div
      key={`primary-day-${index}`}
      className={cn(
        {
          "bg-gray-100": index % 2 == 0,
          "text-orange-400": isWeekend,
        },
        "w-full text-xs flex justify-center items-center"
      )}
      style={{
        width: `${getTimeUnitWidth(taskMode)}px`,
        height: `${GanttConsts.THEADER_HEIGHT - 2}px`,
      }}
    >
      {date.format("YYYY-MM-DD")}
    </div>
  );
};

const renderRangeItem = (
  item: [string, string],
  index: number,
  mode: TaskMode
) => {
  let primaryText = "";
  switch (mode) {
    case "Week":
      primaryText = `${dayjs(item[0]).format("YYYY-MM-DD")} ~ ${dayjs(
        item[1]
      ).format("YYYY-MM-DD")}`;
      break;
    case "Month":
    case "Quarter":
    case "Year":
      primaryText = `${dayjs(item[0]).format("YYYY-MM-DD")} ~ ${dayjs(
        item[1]
      ).format("YYYY-MM-DD")}(${dayjs(item[1]).diff(item[0], "day") + 1}d)`;
      break;
  }

  return (
    <div
      key={`primary-${index}`}
      className={cn(
        "w-full text-sm flex justify-center items-center shadow-lg",
        {
          "bg-gray-100": index % 2 == 0,
        }
      )}
      style={{
        width: `${getTimeHeaderSplitWidth(mode, item as [string, string])}px`,
        height: `${GanttConsts.THEADER_HEIGHT - 2}px`,
      }}
    >
      {primaryText}
    </div>
  );
};
